﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Phone.Controls;
using NextUIKit.Common;
using NextUIKit.Data;

namespace NextUIKit.Controls
{
    public class SlideView : Control
    {
        #region Fields

        #region Const
        private const string SlideViewHostName = "SlideViewHost";
        private const string RightImageHostName = "RightImageHost";
        private const string LeftImageHostName = "LeftImageHost";
        private const string CenterImageHostName = "CenterImageHost";
        private const string CenterImageName = "CenterImage";
        private const string RightImageName = "RightImage";
        private const string LeftImageName = "LeftImage";
        #endregion

        private Grid _slideViewHost;
        private Grid _rightImageHost;
        private Grid _leftImageHost;
        private Grid _centerImageHost;
        private Image _rightImage;
        private Image _centerImage;
        private Image _leftImage;

        private SlideViewItems _slideViewItems;
        private int _snapIndex;//拨动的索引
        private double _horizontalChange;
        private Snapping _oldSnapMode;  //原有的滑动模式
        private DispatcherTimer timer;
        private GestureListener _listener;
        #endregion

        #region DependencyProperties
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(SlideView), new PropertyMetadata(null));

        public event SelectionChangedEventHandler SelectionChanged;

        public int SelectedIndex
        {
            get { return (int)GetValue(SelectedIndexProperty); }
            set { SetValue(SelectedIndexProperty, value); }
        }

        public static readonly DependencyProperty SelectedIndexProperty =
            DependencyProperty.Register("SelectedIndex", typeof(int), typeof(SlideView), new PropertyMetadata(OnSelectedIndexChanged));

        private static void OnSelectedIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SlideView ctrl = (SlideView)d;
            ctrl.OnSelectedIndexChanged((int)e.NewValue, (int)e.OldValue);
        }

        private void OnSelectedIndexChanged(int newValue, int oldValue)
        {
            if (newValue != -1)
            {
                IList removedItems = (null == oldValue) ? new object[0] : new object[] { oldValue };
                IList addedItems = (null == newValue) ? new object[0] : new object[] { newValue };
                if (this.SelectionChanged != null)
                {
                    this.SelectionChanged(this, new SelectionChangedEventArgs(removedItems, addedItems));
                }
            }
        }
        #endregion

        #region Constructor
        public SlideView()
        {
            base.DefaultStyleKey = typeof(SlideView);
            SelectedIndex = -1;
        }
        #endregion

        #region ApplyTemplate
        public override void OnApplyTemplate()
        {
            _slideViewHost = (Grid)GetTemplateChild(SlideViewHostName);
            _rightImageHost = (Grid)GetTemplateChild(RightImageHostName);
            _leftImageHost = (Grid)GetTemplateChild(LeftImageHostName);
            _centerImageHost = (Grid)GetTemplateChild(CenterImageHostName);
            _rightImage = (Image)GetTemplateChild(RightImageName);
            _centerImage = (Image)GetTemplateChild(CenterImageName);
            _leftImage = (Image)GetTemplateChild(LeftImageName);
            
            this.InitPositon();
            this.Hook();
            this.HookImageTap();
            AutoDoIt();
        }

        #endregion

        #region Method

        #region Common
        private void InitPositon()
        {
            _slideViewItems = new SlideViewItems((ObservableCollection<string>)this.ItemsSource, 0);
            ((CompositeTransform)_leftImageHost.RenderTransform).TranslateX = 0;
            SetImage(_leftImage, _slideViewItems.CurUrl);
            ((CompositeTransform)_centerImageHost.RenderTransform).TranslateX = Width;
            SetImage(_centerImage, _slideViewItems.NextUrl);
            ((CompositeTransform)_rightImageHost.RenderTransform).TranslateX = -Width;
            SetImage(_rightImage, _slideViewItems.PreUrl);
        }
        
        private void Hook()
        {
            _listener = GestureService.GetGestureListener(_slideViewHost);

            _slideViewHost.ManipulationStarted += SlideViewHostManipulationStarted;
            _slideViewHost.ManipulationDelta += SlideViewHostManipulationDelta;
            _slideViewHost.ManipulationCompleted += SlideViewHostManipulationCompleted;
            
            _listener.DragStarted += _listener_DragStarted;
            _listener.DragDelta += _listener_DragDelta;
            _listener.DragCompleted += _listener_DragCompleted;
            _listener.Flick += _listener_Flick;
        }

        private void UnHook()
        {
            _slideViewHost.ManipulationStarted -= SlideViewHostManipulationStarted;
            _slideViewHost.ManipulationDelta -= SlideViewHostManipulationDelta;
            _slideViewHost.ManipulationCompleted -= SlideViewHostManipulationCompleted;

            _listener.DragStarted -= _listener_DragStarted;
            _listener.DragDelta -= _listener_DragDelta;
            _listener.DragCompleted -= _listener_DragCompleted;
            _listener.Flick -= _listener_Flick;
        }

        private void HookImageTap()
        {
            _rightImage.Tap += ImageTap;
            _leftImage.Tap += ImageTap;
            _centerImage.Tap += ImageTap;
        }

        private void UnHookImageTap()
        {
            _rightImage.Tap -= ImageTap;
            _leftImage.Tap -= ImageTap;
            _centerImage.Tap -= ImageTap;
        }

        private void BroadCastTheImages()
        {
            Snapping snapMode = Snapping.Left;
            if (_horizontalChange > 0)
            {
                snapMode = Snapping.Right;
            }
            else
            {
                snapMode = Snapping.Left;
            }
            _oldSnapMode = snapMode;
            PreChangePostion(snapMode);
            this.ScrollTo(snapMode);
        }

        private void ScrollTo(Snapping snapMode)
        {
            Storyboard leftScrollSt = new Storyboard();
            double leftTransform = 0.0;
            double centerTransform = 0.0;
            double rightTransform = 0.0;
            if (snapMode == Snapping.Left)
            {
                _snapIndex += 1;
                _slideViewItems.MoveToNext();
                if (Math.Abs(_snapIndex % 3) == 0)
                {
                    leftTransform = 0;
                    centerTransform = Width;
                    rightTransform = -Width;
                    Canvas.SetZIndex(_centerImageHost, -1);
                    SetImage(_rightImage, _slideViewItems.PreUrl);
                    SetImage(_centerImage, _slideViewItems.NextUrl);
                }
                else if (Math.Abs(_snapIndex % 3) == 1)
                {
                    leftTransform = -Width;
                    centerTransform = 0;
                    rightTransform = Width;
                    Canvas.SetZIndex(_rightImageHost, -1);
                    SetImage(_leftImage, _slideViewItems.PreUrl);
                    SetImage(_rightImage, _slideViewItems.NextUrl);
                }
                else if (Math.Abs(_snapIndex % 3) % 3 == 2)
                {
                    centerTransform = -Width;
                    rightTransform = 0;
                    leftTransform = Width;
                    Canvas.SetZIndex(_leftImageHost, -1);
                    SetImage(_centerImage, _slideViewItems.PreUrl);
                    SetImage(_leftImage, _slideViewItems.NextUrl);
                }
            }
            else if (snapMode == Snapping.Right)
            {
                _snapIndex -= 1;
                if (_snapIndex == -1)
                {
                    _snapIndex = 2;
                }
                _slideViewItems.MoveToPre();
                if (Math.Abs(_snapIndex % 3) == 0)
                {
                    leftTransform = 0;
                    centerTransform = Width;
                    rightTransform = -Width;
                    Canvas.SetZIndex(_rightImageHost, -1);
                    SetImage(_rightImage, _slideViewItems.PreUrl);
                    SetImage(_centerImage, _slideViewItems.NextUrl);
                }
                else if (Math.Abs(_snapIndex % 3) == 1)
                {
                    leftTransform = -Width;
                    centerTransform = 0;
                    rightTransform = Width;
                    Canvas.SetZIndex(_leftImageHost, -1);
                    SetImage(_leftImage, _slideViewItems.PreUrl);
                    SetImage(_rightImage, _slideViewItems.NextUrl);
                }
                else if (Math.Abs(_snapIndex % 3) == 2)
                {
                    centerTransform = -Width;
                    rightTransform = 0;
                    leftTransform = Width;
                    Canvas.SetZIndex(_centerImageHost, -1);
                    SetImage(_centerImage, _slideViewItems.PreUrl);
                    SetImage(_leftImage, _slideViewItems.NextUrl);
                }
            }
            DoubleAnimation leftAnimation = this.CreateAnimation((CompositeTransform)_leftImageHost.RenderTransform, CompositeTransform.TranslateXProperty, leftTransform, 800);
            DoubleAnimation centerAnimation = this.CreateAnimation((CompositeTransform)_centerImageHost.RenderTransform, CompositeTransform.TranslateXProperty, centerTransform, 800);
            DoubleAnimation rightAnimation = this.CreateAnimation((CompositeTransform)_rightImageHost.RenderTransform, CompositeTransform.TranslateXProperty, rightTransform, 800);
            leftScrollSt.Children.Add(leftAnimation);
            leftScrollSt.Children.Add(centerAnimation);
            leftScrollSt.Children.Add(rightAnimation);
            leftScrollSt.Begin();
            Invalidate();
            leftScrollSt.Completed += leftScrollSt_Completed;
        }

        /// <summary>
        /// 在方向不边的情况下提前改变控件位置
        /// </summary>
        /// <param name="snapMode"></param>
        private void PreChangePostion(Snapping snapMode)
        {
            if (_oldSnapMode == snapMode)                                                       //方向不改变的情况下
            {
                if (_oldSnapMode == Snapping.Left)
                {
                    if (Math.Abs(_snapIndex % 3) == 0)                                              //Left已经显示,Center准备显示
                    {
                        ((CompositeTransform)_rightImageHost.RenderTransform).TranslateX = Width*2;
                    }
                    else if (Math.Abs(_snapIndex % 3) == 1)                                         //Center已经显示,Right准备显示
                    {
                        ((CompositeTransform)_leftImageHost.RenderTransform).TranslateX = Width*2;
                    }
                    else if (Math.Abs(_snapIndex % 3) == 2)                                         //Right已经显示,Left准备显示
                    {
                        ((CompositeTransform)_centerImageHost.RenderTransform).TranslateX = Width*2;
                    }
                }
                if (_oldSnapMode == Snapping.Right)
                {
                    if (Math.Abs(_snapIndex % 3) == 0)                                              //Left已经显示,Right准备显示
                    {
                        ((CompositeTransform)_centerImageHost.RenderTransform).TranslateX = -Width*2;
                    }
                    else if (Math.Abs(_snapIndex % 3) == 1)                                         //Center已经显示,Left准备显示
                    {
                        ((CompositeTransform)_rightImageHost.RenderTransform).TranslateX = -Width * 2;
                    }
                    else if (Math.Abs(_snapIndex % 3) == 2)                                         //Right已经显示,Center即将显示
                    {
                        ((CompositeTransform)_leftImageHost.RenderTransform).TranslateX = -Width * 2;
                    }
                }
            }
        }

        private DoubleAnimation CreateAnimation(DependencyObject obj, DependencyProperty prop, double value, double milliseconds, EasingMode easing = EasingMode.EaseInOut)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.Duration = TimeSpan.FromMilliseconds(milliseconds);
            doubleAnimation.From = Convert.ToDouble(obj.GetValue(prop));
            doubleAnimation.To = Convert.ToDouble(value);

            doubleAnimation.FillBehavior = FillBehavior.HoldEnd;

            CubicEase cubicEase = new CubicEase();
            cubicEase.EasingMode = easing;
            doubleAnimation.EasingFunction = cubicEase;

            Storyboard.SetTarget(doubleAnimation, obj);
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(prop));

            return doubleAnimation;
        }

        private void Invalidate()
        {
            UnHook();
            UnHookImageTap();
        }

        private void AutoDoIt()
        {
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(2000);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        private void StopAuto()
        {
            timer.Stop();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            this.BroadCastTheImages();
        }   
        
        #region SetImageUtilMethod

        private void SetImage(Image image, string url)
        {
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.UriSource = new Uri(url, UriKind.Absolute);
            image.Source = bitmapImage;
        }
        private string GetElemetAtIndex(int index)
        {
            ObservableCollection<string> strs = (ObservableCollection<string>)ItemsSource;
            string resultStr = "";
            if (index % GetAllImagesCount() < 0)
            {
                resultStr = strs[index % GetAllImagesCount() + GetAllImagesCount()];
            }
            else
            {
                resultStr = strs[index % GetAllImagesCount()];
            }
            return resultStr;
        }

        private int GetAllImagesCount()
        {
            return ((IList<string>)this.ItemsSource).Count;//这个地方默认是个string 字符串集合
        }

        #endregion

        #endregion


        #endregion

        #region Delegate
        void SlideViewHostManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            e.Complete();
            e.Handled = true;
        }

        void _listener_DragStarted(object sender, DragStartedGestureEventArgs e)
        {
            StopAuto();
            e.Handled = true;
        }

        void SlideViewHostManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            e.Complete();
            e.Handled = true;
        }

        void _listener_DragDelta(object sender, DragDeltaGestureEventArgs e)
        {
            _horizontalChange = e.HorizontalChange;
            CompositeTransform leftTransform = (CompositeTransform)_leftImageHost.RenderTransform;
            CompositeTransform centerTransform = (CompositeTransform)_centerImageHost.RenderTransform;
            CompositeTransform rightTransform = (CompositeTransform)_rightImageHost.RenderTransform;
            leftTransform.TranslateX += e.HorizontalChange;
            centerTransform.TranslateX += e.HorizontalChange;
            rightTransform.TranslateX += e.HorizontalChange;
            e.Handled = true;
        }

        void _listener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
        {
            BroadCastTheImages();
            e.Handled = true;
        }

        void SlideViewHostManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            e.Handled = true;
        }

        void _listener_Flick(object sender, FlickGestureEventArgs e)
        {
            e.Handled = true;
        }

        void leftScrollSt_Completed(object sender, EventArgs e)
        {
            Canvas.SetZIndex(_leftImageHost, 0);
            Canvas.SetZIndex(_centerImageHost, 0);
            Canvas.SetZIndex(_rightImageHost, 0);
            Hook();
            HookImageTap();
        }

        void ImageTap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            SelectedIndex = _slideViewItems.ShowIndex;
        }

        
        #endregion
    }
}
